home *** CD-ROM | disk | FTP | other *** search
/ PC World Interactive 4 / PC World Interactive 4.iso / online / appbar.EXE / cppsrc / AppBarWin.cpp < prev    next >
C/C++ Source or Header  |  1996-09-20  |  14KB  |  517 lines

  1. // *********************************************************
  2. // AppBar -- Advanced Menu bar for Windows 95/NT
  3. // All code Copyright (C) 1995, 1996 by Mike Perham
  4. // mperham@cs.cornell.edu
  5. // 
  6. // This code MAY NOT be used for any other program without
  7. // my permission and is forbidden in any shareware/commercial
  8. // program.  This code is provided for educational use only
  9. // and there are no guarantees or promises implied.  Blah blah
  10. // *********************************************************
  11.  
  12. //////////////////////////////////////////////////////////////////////////////////
  13. //  AppBarWin - the Window
  14. //        This file encapsulates all functions that affect what the user sees
  15. //        on the screen and all UI elements.
  16. //////////
  17.  
  18. #include "appbar.h"
  19. #include "globals.h"
  20.  
  21. #ifdef _DEBUG
  22.     #undef THIS_FILE
  23.     static char THIS_FILE[] = __FILE__;
  24.     #define new DEBUG_NEW
  25. #endif
  26.  
  27. BEGIN_MESSAGE_MAP(AppBarWin, CWnd)
  28.     //{{AFX_MSG_MAP(AppBarWin)
  29.     ON_WM_ACTIVATE()
  30.     ON_WM_NCMOUSEMOVE()
  31.     ON_WM_NCRBUTTONDOWN()
  32. //    ON_WM_NCLBUTTONDBLCLK()
  33.     ON_WM_SHOWWINDOW()
  34.     ON_WM_TIMECHANGE()
  35.     ON_WM_WINDOWPOSCHANGED()
  36.     ON_WM_TIMER()
  37.     ON_WM_CLOSE()
  38.     ON_MESSAGE(WM_HOTKEY, OnHotKey)
  39.     ON_MESSAGE(WM_DISPLAYCHANGE, OnDisplayChange)
  40.     ON_MESSAGE(WM_POWERBROADCAST, OnPowerBroadcast)
  41.     ON_COMMAND(ID_ABOUT, OnAbout)
  42.     ON_COMMAND(ID_EDIT, OnEdit)
  43.     ON_COMMAND(ID_OPTIONS, OnOptions)
  44.     ON_COMMAND(ID_EXITAPPBAR, OnExit)
  45.     ON_COMMAND_RANGE(101, 40000, OnAppSelect)
  46.     //}}AFX_MSG_MAP
  47. END_MESSAGE_MAP()
  48.  
  49. void inline AppBarWin::ab_message(char *msg)
  50. {
  51.     MessageBox(msg, "AppBar", MB_OK | MB_ICONINFORMATION);
  52. }
  53.  
  54. /////////////////////////////////////////////////////////////////////////////
  55. // AppBarWin message handlers
  56.  
  57. BOOL AppBarWin::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle,
  58.                          int x, int y, int width, int height, HWND ParentWnd, HMENU nID, LPVOID pContext)
  59. {
  60.     BOOL t = CWnd::CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
  61.                             x, y, width, height, ParentWnd, nID, pContext);
  62.  
  63.     if (sv.newshell) {
  64.         BOOL ab;
  65.         abd.cbSize = sizeof(APPBARDATA);
  66.         abd.hWnd = m_hWnd;
  67.         abd.uCallbackMessage = NULL;
  68.         abd.uEdge = (uv.bottom ? ABE_BOTTOM : ABE_TOP);
  69.         ab = SHAppBarMessage(ABM_NEW, &abd);
  70.         if (ab && uv.autohide) {
  71.             abd.lParam = TRUE;
  72.             if (!SHAppBarMessage(ABM_SETAUTOHIDEBAR, &abd)) {
  73.                 ab_message(ERROR_AUTOHIDING);
  74.                 uv.autohide = FALSE;
  75.             }
  76.         } else if (ab) {
  77.             abd.rc.top = 0;
  78.             abd.rc.left = 0;
  79.             abd.rc.right = GetSystemMetrics(SM_CXSCREEN);
  80.             abd.rc.bottom = GetSystemMetrics(SM_CYSCREEN);
  81.             SHAppBarMessage(ABM_QUERYPOS, &abd);
  82.             abd.rc.top = (uv.bottom ? abd.rc.bottom - AB_HEIGHT : abd.rc.top);
  83.             MoveWindow(abd.rc.left, abd.rc.top, AB_WIDTH, AB_HEIGHT, FALSE);
  84.             abd.rc.bottom = abd.rc.top + AB_HEIGHT;
  85.             abd.rc.right = AB_WIDTH;
  86.             SHAppBarMessage(ABM_SETPOS, &abd);
  87.         }
  88.     }
  89.         // Insert applications into menu
  90.     UpdateMenu();
  91.     return t;
  92. }
  93.  
  94. void AppBarWin::OnEdit()
  95. {
  96.     EditDlg ed(this);
  97.     ed.DoModal();
  98. }
  99.  
  100. void AppBarWin::OnAbout()
  101. {
  102.     AboutDlg ad;
  103.     ad.DoModal();
  104. }
  105.  
  106. void AppBarWin::OnOptions()
  107. {    
  108.     OptDlg od;
  109.     od.DoModal();
  110. }
  111.  
  112. void AppBarWin::OnExit()
  113. {
  114.     ATOM adam = GlobalFindAtom("AppBar HotKey");
  115.     UnregisterHotKey(m_hWnd, adam);
  116.     GlobalDeleteAtom(adam);
  117.     ab.ExitAppBar(FALSE);
  118. }
  119.  
  120. void AppBarWin::OnAppSelect(UINT id)
  121. {
  122.     app_struct *find = find_appId(id);
  123.     ASSERT(find);
  124.     ab.ExecuteApplication(find);
  125. }
  126.  
  127. LONG AppBarWin::OnHotKey(UINT u, LONG l)
  128. {
  129.     int bitmask;
  130.  
  131.     HideAppBar(FALSE);
  132.     SetForegroundWindow();
  133.     // this is the code for pressing the Alt key down
  134.     // so we can make the menu highlight
  135.     bitmask = 0x00000001 | 38<<16 | 1<<24 | 1<<29;
  136.     PostMessage(WM_SYSKEYDOWN, VK_MENU, bitmask);
  137.     bitmask = 0x00000001 | 38<<16 | 3<<30;
  138.     PostMessage(WM_SYSKEYUP, VK_MENU, bitmask);
  139.     return TRUE;
  140. }
  141.  
  142. void AppBarWin::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
  143. {
  144.     CWnd::OnActivate(nState, pWndOther, bMinimized);
  145.     if ((nState == WA_INACTIVE) && uv.autohide) {
  146.         HideAppBar(TRUE);
  147.         KillTimer(HIDE_TIMER);
  148.     }
  149.     if (sv.newshell) {
  150.         abd.cbSize = sizeof(APPBARDATA);
  151.         abd.hWnd = m_hWnd;
  152.         SHAppBarMessage(ABM_ACTIVATE, &abd);
  153.     }
  154. }
  155.  
  156. void AppBarWin::OnNcMouseMove(UINT nFlags, CPoint point) 
  157. {
  158.     if (uv.autohide)
  159.         if (!IsShown) {
  160.             POINT pt;
  161.             GetCursorPos(&pt);
  162.             // Don't show AppBar if the mouse moves in the right 10% of the screen.
  163.             // This is so using the max/min buttons doesn't accidently unhide
  164.             // AppBar.
  165.             if (pt.x < sv.width - (int)(sv.width/10))
  166.                 HideAppBar(FALSE);
  167.             timer = SetTimer(HIDE_TIMER, 500, NULL);
  168.           } else {
  169.             if (timer)
  170.                 KillTimer(HIDE_TIMER);
  171.             timer = SetTimer(HIDE_TIMER, 500, NULL);
  172.         }
  173.     CWnd::OnNcMouseMove(nFlags, point);
  174. }
  175. /*
  176. void AppBarWin::OnNcLButtonDblClk(UINT nHitTest, CPoint pt) 
  177. {
  178.     ATOM adam = GlobalFindAtom("AppBar HotKey");
  179.     UnregisterHotKey(m_hWnd, adam);
  180.     GlobalDeleteAtom(adam);
  181.     ab.ExitAppBar(FALSE);
  182. }
  183. */
  184. // when AppBar is closed via the Task Manager
  185.  
  186. void AppBarWin::OnClose() 
  187. {
  188.     ATOM adam = GlobalFindAtom("AppBar HotKey");
  189.     UnregisterHotKey(m_hWnd, adam);
  190.     GlobalDeleteAtom(adam);
  191.     ab.ExitAppBar(FALSE);
  192. }
  193.  
  194. void AppBarWin::OnNcRButtonDown(UINT nHitTest, CPoint pt) 
  195. {
  196.     CWnd::OnNcRButtonDown(nHitTest, pt);
  197.     CMenu menu;
  198.     VERIFY(menu.LoadMenu(IDR_MENU));
  199.     CMenu *Popup = menu.GetSubMenu(0);
  200.     ASSERT(Popup);
  201.     Popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, 
  202.                           pt.x, pt.y, AfxGetMainWnd());
  203. }
  204.  
  205. void AppBarWin::OnShowWindow(BOOL bShow, UINT nStatus) 
  206. {
  207.     CWnd::OnShowWindow(bShow, nStatus);
  208.     if (!RegisterHotKey(m_hWnd, GlobalAddAtom("AppBar HotKey"), MOD_ALT | MOD_CONTROL, 0x5A /*z*/))
  209.         if (!RegisterHotKey(m_hWnd, GlobalAddAtom("AppBar HotKey"), MOD_ALT | MOD_CONTROL, 0x41 /*a*/))
  210.             ab_message(ERROR_HOTKEY);
  211.     IsShown = TRUE;
  212.     SyncTime();
  213. }
  214.  
  215. void AppBarWin::OnTimeChange()
  216. {
  217.     ModifyTime();
  218.     CWnd::OnTimeChange();
  219. }
  220.  
  221. void AppBarWin::OnTimer(UINT id) 
  222. {
  223.     if (id == TIME_UPDATE)
  224.         ModifyTime();
  225.       else if (id == HIDE_TIMER) {
  226.         if (uv.autohide)
  227.             if (GetActiveWindow() != this) {
  228.                 POINT pt;
  229.                 GetCursorPos(&pt);
  230.                 if (WindowFromPoint(pt) != this) {
  231.                     timer = NULL;
  232.                     KillTimer(HIDE_TIMER);
  233.                     HideAppBar(TRUE);
  234.                 }
  235.             }
  236.       } else if (id == SYNC_TIMER) {
  237.           KillTimer(TIME_UPDATE);
  238.           KillTimer(SYNC_TIMER);
  239.           SetTimer(TIME_UPDATE, 10000, NULL);
  240.           ModifyTime();
  241.     }
  242.     CWnd::OnTimer(id);
  243. }
  244.  
  245. void AppBarWin::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos)
  246. {
  247.     CWnd::OnWindowPosChanged(lpwndpos);
  248.     if (sv.newshell) {
  249.         abd.cbSize = sizeof(APPBARDATA);
  250.         abd.hWnd = m_hWnd;
  251.         SHAppBarMessage(ABM_WINDOWPOSCHANGED, &abd);
  252.     }
  253. }
  254.  
  255. LONG AppBarWin::OnPowerBroadcast(UINT event, LONG data)
  256. {
  257.     if (sv.power) {
  258.         SYSTEM_POWER_STATUS sps;
  259.         GetSystemPowerStatus(&sps);
  260.         sv.battery = (sps.ACLineStatus ? FALSE : TRUE);
  261.         ModifyTime();
  262.     }
  263.     return TRUE;
  264. }
  265.  
  266. LONG AppBarWin::OnDisplayChange(UINT wParam, LONG lParam)
  267. {
  268.     if (sv.newshell) {
  269.         sv.width = GetSystemMetrics(SM_CXSCREEN);
  270.         sv.height = GetSystemMetrics(SM_CYSCREEN);
  271.         MoveWindow(0, (uv.bottom ? sv.height - AB_HEIGHT : 0), AB_WIDTH, AB_HEIGHT, TRUE);
  272.     }
  273.     return TRUE;
  274. }
  275.  
  276. /////////////////////////////////////////////////////////////////////////////
  277. //    Add-on functions
  278. ///////////
  279.  
  280.     // Syncs AppBar's timer with the system time
  281. void AppBarWin::SyncTime(void)
  282. {
  283.     SYSTEMTIME st;
  284.  
  285.     GetSystemTime(&st);
  286.     // install timer that goes off at next 10 sec interval (10, 20, 30, etc.)
  287.     SetTimer(SYNC_TIMER, ((9-(st.wSecond%10))*1000)+(1000-st.wMilliseconds), NULL);
  288. }
  289.  
  290. ///////////////////////////////////////////////////////////////
  291. // Based on function in Microsoft Systems Journal
  292. // March 1996 by Jeffrey Richter
  293. ////
  294.  
  295. void AppBarWin::Slide(int newy)
  296. {
  297.     int y, t_start, t_end, t_curr, hide_time;
  298.     RECT start;
  299.  
  300.     hide_time = (IsShown ? 300 : 200);
  301.     GetWindowRect(&start);
  302.     t_start = GetTickCount();
  303.     t_end = t_start + hide_time;
  304.     // Raise the thread priority so that the slide is smooth rather than jerky
  305.     // This is not necessary on a Pentium Pro 200Mhz running NT 4.0  :)
  306.     // SetThreadPriority(ab.m_hThread, THREAD_PRIORITY_ABOVE_NORMAL);
  307.     while ((t_curr = GetTickCount()) < t_end) {
  308.         y = start.top - (start.top - newy) * (int) (t_curr - t_start) / hide_time;
  309.         SetWindowPos(NULL, 0, y, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
  310.         UpdateWindow();
  311.     }
  312.     SetWindowPos(NULL, 0, newy, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
  313.     UpdateWindow();
  314.     // SetThreadPriority(ab.m_hThread, THREAD_PRIORITY_NORMAL);
  315. }
  316.  
  317. //////////// hides or shows AppBar, depending on "hide" variable
  318.  
  319. void AppBarWin::HideAppBar(BOOL hide)
  320. {
  321.     int newy;
  322.     BOOL drag = TRUE;
  323.  
  324.     if (!hide && IsShown)
  325.         return;
  326.  
  327.     // if you want AppBar to always slide, just comment out this call
  328.     if (sv.newshell)    
  329.         SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &drag, 0);
  330.  
  331.     if (hide) {
  332.         newy = (uv.bottom ? sv.height - 2 : -(AB_HEIGHT - 2));
  333.         IsShown = FALSE;
  334.         drag ? Slide(newy) : SetWindowPos(NULL, 0, newy, 0, 0,
  335.                                     SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
  336.       } else {
  337.         newy = (uv.bottom ? sv.height - AB_HEIGHT : 0);
  338.         IsShown = TRUE;
  339.         drag ? Slide(newy) : SetWindowPos(NULL, 0, newy, 0, 0,
  340.                                     SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
  341.         ModifyTime();
  342.     }
  343. }
  344.  
  345. //////////////////////////////////////////////////////////////
  346.  
  347. void AppBarWin::UpdateMenu(void)
  348. {
  349.     int a = 1, m = 1;                // current app/menu
  350.     app_struct *app;
  351.     menu_struct *menu, *firstapp;   // curr menu/first menu with an app
  352.     CMenu hmenu, ab_menu;
  353.     app_list *curapplist, *prevapplist;
  354.  
  355.     kill_applist();
  356.     ab_menu.CreateMenu();
  357.  
  358.     // empty AppBar ???
  359.     if (!glob_menu) {
  360.         applist = NULL;
  361.         SetMenu(&ab_menu);
  362.         ab_menu.Detach();
  363.         DrawMenuBar();
  364.         return;
  365.     }
  366.  
  367.     // find the first non-empty menu
  368.     for (menu = glob_menu, firstapp = NULL; menu; menu = menu->nextmenu)
  369.         if (menu->nextapp) {
  370.             firstapp = menu;
  371.             break;
  372.         }
  373.  
  374.     for (menu = glob_menu; menu; menu = menu->nextmenu) {
  375.         hmenu.CreateMenu();
  376.         for (app = menu->nextapp; app; app = app->nextapp) {
  377.             if (app->separator)                    // Put in separator
  378.                 hmenu.AppendMenu(MF_SEPARATOR, 0, (LPCTSTR)NULL);
  379.             hmenu.AppendMenu(MF_STRING, (m*100 + a), app->appname);
  380.             if (firstapp->nextapp == app) {
  381.                 applist = new app_list;
  382.                 curapplist = applist;
  383.               }    else {
  384.                 curapplist = new app_list;
  385.                 prevapplist->next = curapplist;
  386.             }
  387.             curapplist->appId = m*100 + a;
  388.             curapplist->app = app;                                
  389.             curapplist->next = NULL;
  390.             prevapplist = curapplist;
  391.             a++;
  392.         }
  393.         ab_menu.InsertMenu(m, MF_BYPOSITION | MF_POPUP,
  394.                             (UINT)hmenu.m_hMenu, menu->menuname);
  395.         hmenu.Detach();
  396.         a = 1;
  397.         m++;
  398.     }
  399.     SetMenu(&ab_menu);
  400.     ab_menu.Detach();
  401.     DrawMenuBar();
  402.      return;
  403. }
  404.  
  405. // Update time on menubar every minute
  406.  
  407. void AppBarWin::ModifyTime(void)
  408. {
  409.     char string[105] = "";
  410.     char time[20] = "";
  411.     char date[25] = "";
  412.     char mem[10] = "";
  413.     char user[40] = "";
  414.     char batt[20] = "";
  415.     static BOOL played_wav;
  416.     SYSTEM_POWER_STATUS sps;
  417.  
  418.     // if AppBar is hiding, why bother drawing?
  419.     if (IsShown) {
  420.         if (uv.user)
  421.             sprintf(user, "%s  ", sv.user);
  422.         
  423.         if (uv.time) {
  424.             GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_NOSECONDS, NULL, 
  425.                         NULL, time, sizeof(time));
  426.             strcat(time, "  ");
  427.         }
  428.  
  429.         if (uv.date) {
  430.             GetDateFormat(LOCALE_SYSTEM_DEFAULT, NULL, NULL, NULL, 
  431.                         date, sizeof(date));
  432.             strcat(date, "  ");
  433.         }
  434.         
  435.         if (uv.memory) {
  436.             MEMORYSTATUS ms;
  437.             GlobalMemoryStatus(&ms);
  438.             sprintf(mem, "%dk ", (int)ms.dwAvailPhys/1024);
  439.         }
  440.  
  441.         if (sv.power)
  442.             if (sv.battery) {
  443.                 GetSystemPowerStatus(&sps);
  444.                 sprintf(batt, "%d%%", sps.BatteryLifePercent);
  445.                 if (sps.BatteryLifePercent == 255)                // unknown percentage
  446.                     sprintf(batt, "--%%");
  447.             }
  448.  
  449.         // final string to print on AppBar
  450.         sprintf(string, "%s%s%s%s%s", user, time, date, mem, batt);
  451.  
  452.         SIZE s;
  453.         int x,y;
  454.         TEXTMETRIC tm;
  455.         COLORREF c;
  456.         CFont cf, *oldcf;
  457.         NONCLIENTMETRICS ncm;
  458.  
  459.         CWindowDC cdc(this);
  460.         if (sv.newshell) {
  461.             ncm.cbSize = sizeof(NONCLIENTMETRICS);
  462.             SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
  463.             cf.CreateFontIndirect(&(ncm.lfMenuFont));
  464.             oldcf = (CFont *) cdc.SelectObject(&cf);
  465.         }
  466.         c = cdc.SetTextColor(GetSysColor(COLOR_MENUTEXT));
  467.         cdc.SetBkColor(GetSysColor(COLOR_MENU));
  468.         GetTextExtentPoint32(cdc.m_hDC, string, strlen(string), &s);
  469.         x = AB_WIDTH - s.cx - 7;
  470.         cdc.GetTextMetrics(&tm);
  471.         y = (int) ((AB_HEIGHT - tm.tmHeight) / 2);
  472.             // Draw all the stats at (x,y)
  473.         DrawMenuBar();
  474.         cdc.TextOut(x, y, string, strlen(string));
  475.         if (sv.power)
  476.             if (sv.battery) {
  477.                 if (sps.BatteryLifePercent > 25)
  478.                     cdc.SetTextColor(GREEN);
  479.                   else if (sps.BatteryLifePercent > 10)
  480.                     cdc.SetTextColor(YELLOW);
  481.                   else
  482.                     cdc.SetTextColor(RED);
  483.                 GetTextExtentPoint32(cdc.m_hDC, batt, strlen(batt), &s);
  484.                 x = AB_WIDTH - s.cx - 7;
  485.                 cdc.TextOut(x, y, batt, strlen(batt));
  486.             }
  487.         if (sv.newshell) {
  488.             cdc.SelectObject(oldcf); 
  489.             cf.DeleteObject();
  490.         }
  491.         cdc.SetTextColor(c);
  492.     }   // end if (IsShown)
  493.  
  494.     if (uv.chime) {
  495.         SYSTEMTIME st;
  496.         GetSystemTime(&st);
  497.  
  498.         // if it's the top of the hour and we haven't already played this minute...
  499.         if ((st.wMinute == 0) && (!played_wav)) {
  500.             played_wav = TRUE;
  501.             if (!PlaySound(uv.wavfile, NULL, SND_ASYNC | SND_FILENAME))
  502.                 ab_message(ERROR_PLAYING_WAV);
  503.           } else if (st.wMinute == 1)
  504.             played_wav = FALSE;
  505.     }
  506. }
  507.  
  508. AppBarWin::AppBarWin()
  509. {
  510.     CWnd::CWnd();
  511. }
  512.  
  513. AppBarWin::~AppBarWin()
  514. {
  515.     CWnd::~CWnd();
  516. }
  517.